package com.iniapp.app.jsf;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.faces.component.UICommand;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.component.html.HtmlCommandButton;
import javax.faces.component.html.HtmlCommandLink;
import javax.faces.context.FacesContext;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JsfViewRoot extends javax.faces.component.UIViewRoot{

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Override
	public void encodeBegin(FacesContext context) throws IOException {
		travelComponent(context, this);
		super.encodeBegin(context);
	}

	private void travelComponent(FacesContext context, UIComponent current){
		//logger.trace("current component -> {}, type-> {}", current.getId(), current.getClass());
		if(current instanceof UINamingContainer){
			// we are within some method of UIComponent
			UIComponent childrenHolderFacet = current.getFacets().get("javax.faces.component.COMPOSITE_FACET_NAME");
			if(childrenHolderFacet!=null){
				List<UIComponent> children = childrenHolderFacet.getChildren();
				if(children!=null){
					Iterator<UIComponent> childrenIt = children.iterator();
					while(childrenIt.hasNext()){
						travelComponent(context, childrenIt.next());
					}
				}
			}
		}
		
		if(current instanceof UICommand){
			UICommand button = (UICommand) current;
			applyAccessControl(context, button);
		}
		if(current instanceof HtmlCommandButton){
			HtmlCommandButton button = (HtmlCommandButton) current;
			applyAccessControl(context, button);
		}		
		if(current instanceof HtmlCommandLink){
			HtmlCommandLink button = (HtmlCommandLink) current;
			applyAccessControl(context, button);
		}
		
		List<UIComponent> children = current.getChildren();
		if(children!=null && children.size()>0){
			for (UIComponent child : children) {
				travelComponent(context, child);
			}
		}
		
	}
	
	private void applyAccessControl(FacesContext context, UIComponent component){
		Identity identity = JsfSecurityUtil.getCurrentIdentity();
		if(identity!=null && identity.isLoggedIn()){
			String action = context.getViewRoot().getViewId() + "#"+component.getId();
			logger.trace("Checking Action authorization for : {}", action);
			{
				if(component.getId()!=null && component.getId().endsWith("BtnIcon")){
					//Icon protection is the same as button if following id convention: xxxBtn <-> xxxBtnIcon
					action = action.replaceAll("Icon", "");
				}
			}
			boolean granted = JsfSecurityUtil.isActionGranted(action, identity.getGrantedActions());
			if(granted){
				logger.trace("granted");
			}else{
				logger.trace("denied");
				setDisabled(component);
			}
		}
	}

	public static void setDisabled(UIComponent component) {

		if (PropertyUtils.isWriteable(component, "disabled")) {
			setProperty(component, "disabled", Boolean.TRUE);
		}
		if (PropertyUtils.isWriteable(component, "onclick")) {
			setProperty(component, "onclick", "return false;");
		}
		setProperty(component, "style", "color:gray;cursor:text;");

	}

	private static void setProperty(UIComponent component, String attribute, Object value) {
		try {
			PropertyUtils.setProperty(component, attribute, value);
		} catch (Exception e) {
			
		}
	}

}
